package ldh.maker.controller;

import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.*;
import javafx.stage.Stage;
import javafx.util.Callback;
import ldh.database.Column;
import ldh.database.Table;
import ldh.maker.component.ColumnUi;
import ldh.maker.db.EnumDb;
import ldh.maker.freemaker.EnumStatusMaker;
import ldh.maker.util.*;
import ldh.maker.vo.DBConnectionData;
import ldh.maker.vo.EnumData;
import ldh.maker.vo.TreeNode;
import org.controlsfx.validation.Severity;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
import org.h2.command.dml.Call;

import java.net.URL;
import java.sql.Connection;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created by ldh on 2017/4/19.
 */
public class CreateEnumController implements Initializable {

    ValidationSupport validationSupport = new ValidationSupport();

    @FXML TextField packageText;
    @FXML TextField nameText;
    @FXML TextField descText;
    @FXML TextField valueText;
    @FXML TextField value1Text;
    @FXML ChoiceBox<String> choiceBox;
    @FXML Label value1Label;
    @FXML ListView<String> valueList;
    @FXML TextArea codeTextArea;
    @FXML ListView<String> columnValueList;

    private TreeItem<TreeNode> treeItem;
    private String key;
    private Column column;
    private Table table;
    private String dbName;
    private Callback callback;
    private Stage stage;

    public void setStage(Stage stage) {
        this.stage = stage;
    }

    @FXML void add() {
        if(validationSupport.isInvalid()) {
            DialogUtil.show(Alert.AlertType.WARNING, "填写错误", "请按照要求填写");
            return;
        }
        String type = choiceBox.getSelectionModel().getSelectedItem();
        if (type.equals("Enum")) {
            valueList.getItems().add(valueText.getText().trim());
            createCode();
            return;
        }
        Object obj = CommonUtil.to(value1Text.getText().trim(), type);
        if (obj == null) {
            DialogUtil.show(Alert.AlertType.WARNING, "填写错误", "请按照要求填写");
            return;
        }
        valueList.getItems().add(valueText.getText().trim() + "(" + value1Text.getText().trim() + ")" + "--" + descText.getText().trim());
        createCode();
        valueText.setText("");
        value1Text.setText("");
        descText.setText("");
    }

    private void createCode() {
        String type = choiceBox.getSelectionModel().getSelectedItem();
        if (valueList.getItems().size() < 1) return;
        String value = valueList.getItems().get(0);
        EnumStatusMaker enumStatusMaker = new EnumStatusMaker();
        enumStatusMaker.pack(packageText.getText().trim())
                .name(nameText.getText().trim())
                .choiceType(type)
                ;
        if (!type.equals("Enum")) {
            Class clazz = CommonUtil.to(CommonUtil.getValue(value), type).getClass();
            enumStatusMaker.type(clazz).columnName(column.getName()).tableName(table.getName());
        }
        for (String str : valueList.getItems()) {
            if (type.equals("Enum")) {
                EnumData ed = new EnumData(str, CommonUtil.getDesc(str));
                enumStatusMaker.addValue(str, ed);
            } else {
                Object v = CommonUtil.to(CommonUtil.getValue(str), type);
                EnumData ed = new EnumData(v, CommonUtil.getDesc(str));
                enumStatusMaker.addValue(CommonUtil.getName(str), ed);
            }
        }
        String code = enumStatusMaker.toString();
        codeTextArea.setText(code);
        EnumFactory.getInstance().put(key, enumStatusMaker);
        try {
            EnumDb.update(treeItem.getValue().getParent().getId());
            callback.call(null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setPackage(String packageUrl) {
        EnumStatusMaker esm = EnumFactory.getInstance().get(key);
        if (esm == null) {
            packageText.setText(packageUrl);
        }
    }

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        validationSupport.registerValidator(packageText, Validator.createEmptyValidator("包路径不能为空"));
        validationSupport.registerValidator(nameText, Validator.createEmptyValidator("名称不能为空"));
        validationSupport.registerValidator(valueText, Validator.createEmptyValidator("值不能为空"));

        choiceBox.setItems(FXCollections.observableArrayList(Arrays.asList("Enum", "Enum(String)", "Enum(int)", "Enum(short)", "Enum(byte)", "Enum(boolean)")));

        choiceBox.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends String> observable, String oldValue, String newValue)->{
            choiceBoxEvent();
        });

        validationSupport.registerValidator(choiceBox, Validator.createEmptyValidator("类型不能为空"));
        validationSupport.registerValidator(descText, Validator.createEmptyValidator("描述不能为空"));

        ContextMenu contextMenu = new ContextMenu();
        MenuItem delete = new MenuItem("删除");
        MenuItem edit = new MenuItem("修改");
        delete.setOnAction(e->deleteValue());
        edit.setOnAction(e->editValue());
        contextMenu.getItems().addAll(delete, edit);
        valueList.setContextMenu(contextMenu);
    }

    private void deleteValue() {
        String value = valueList.getSelectionModel().getSelectedItem();
        if (value == null) return;
        EnumStatusMaker esm = EnumFactory.getInstance().get(key);
        String vv = value.substring(0, value.indexOf("("));
        esm.remove(vv);
        valueList.getItems().remove(value);
        String code = esm.toString();
        codeTextArea.setText(code);
        EnumFactory.getInstance().put(key, esm);
        try {
            EnumDb.update(treeItem.getValue().getParent().getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    void editValue() {
        String value = valueList.getSelectionModel().getSelectedItem();
        if (value == null) return;
        EnumStatusMaker esm = EnumFactory.getInstance().get(key);
        String vv = value.substring(0, value.indexOf("("));
        esm.remove(vv);
        valueList.getItems().remove(value);
        String code = esm.toString();
        codeTextArea.setText(code);
        EnumFactory.getInstance().put(key, esm);
        try {
            EnumDb.update(treeItem.getValue().getParent().getId());
        } catch (Exception e) {
            e.printStackTrace();
        }
        value = value.substring(value.indexOf("(")+1);
        String value1 = value.substring(0, value.indexOf(")"));
        value = value.substring(value.indexOf(")") + 1);
        String value2 = value.substring(2);
        valueText.setText(vv);
        value1Text.setText(value1);
        descText.setText(value2);
    }

    private void choiceBoxEvent() {
        String selectValue = choiceBox.getSelectionModel().getSelectedItem();
        if (selectValue.equals("Enum")) {
            value1Label.setVisible(false);
            value1Text.setVisible(false);
        } else {
            value1Label.setVisible(true);
            value1Text.setVisible(true);
        }
        valueList.getItems().clear();
    }

    public void setKey(String key) {
        this.key = key;
        EnumStatusMaker esm = EnumFactory.getInstance().get(key);
        if (esm != null) {
            packageText.setText(esm.getPack());
            nameText.setText(esm.getClassName());
            choiceBox.getSelectionModel().select(esm.getChoiceType());
            for (Map.Entry<String, EnumData> entry : esm.getValues().entrySet()) {
                valueList.getItems().add(entry.getKey() + "(" + entry.getValue().getValue().toString() + ")" + "--" + entry.getValue().getDesc());
            }
            String code = esm.toString();
            codeTextArea.setText(code);
        }
    }

    public void setCallback(Callback callback) {
        this.callback = callback;
    }

    public void setData(Column column, Table table, String dbName) {
        this.column = column;
        this.table = table;
        this.dbName = dbName;

        nameText.setText(table.getJavaName() + FreeMakerUtil.firstUpper(column.getProperty()) + "Enum");
        choiceBox.getSelectionModel().select("Enum(" + column.getDefaultPropertyClass().getSimpleName().toLowerCase() + ")");

        try {
            Object obj = treeItem.getParent().getValue().getData();
            if (obj instanceof DBConnectionData) {
                String db = treeItem.getValue().getData().toString();
                Connection connection = ConnectionFactory.getConnection((DBConnectionData)obj, db);
                List<Object> values = EnumDb.getValues(connection, table.getName(), column.getName());
                columnValueList.getItems().addAll(values.stream().map(e->e.toString()).collect(Collectors.toList()));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void setTreeItem(TreeItem<TreeNode> treeItem) {
        this.treeItem = treeItem;
    }

    public void saveData(ActionEvent actionEvent) {
        createCode();
        if (stage != null) stage.close();
    }
}
